perm filename MEMTEX.TXT[PAS,DEK] blob sn#675875 filedate 1982-09-01 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00009 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	On Sep 1, 1982 I made a version of TeX that was designed to help spot
C00004 00003	@p function get_avail : pointer {single-word node allocation}
C00006 00004	@d free_avail(#)== {single-word node liberation}
C00007 00005	@p function get_node(@!s:integer):pointer {variable-size node liberation}
C00009 00006	@ @<Try to allocate...@>=
C00010 00007	@ @<Check single-word...@>=
C00011 00008	15: begin font_in_short_display←undefined_font short_display(n)
C00012 00009	@* \[54] System-dependent changes.
C00014 ENDMK
C⊗;
On Sep 1, 1982 I made a version of TeX that was designed to help spot
"memory wastage" errors.

Basically, the getavail and getnode routines were changed so that they
never recycled any nodes. Then the nodes that were not freed at the
end of the program were erroneous; and a second pass could be used to
identify the source of the erroneous nodes.

The following pages of this file show the additions I made to the
ordinary change file, in order to make MEMTEX.

(To create the FREE.TMP file, I used TeX's debugger, saying
#11 0 16 0
where 16 was a new option that writes that new file. When FREE.TMP
exists, INITEX (but not with a preloaded format) will load it.)
@p function get_avail : pointer; {single-word node allocation}
var p:pointer; {the new node being got}
begin p←avail; {get top location in the |avail| stack}
if p≠null then avail←link(avail) {and pop it off}
else if mem_end<mem_max then {or go into virgin territory}
	begin incr(mem_end); p←mem_end;
	end
else	begin runaway; {if memory is exhausted, display possible runaway text}
	overflow("memory size",mem_max-mem_base); {quit; all one-word nodes are busy}
	end;
link(p)←null; {provide an oft-desired initialization of the new node}
stat incr(dyn_used);@+tats@;{maintain statistics}
if not was_free[p] then
	begin @{@/
	'*************breakpoint*************';@/
	'***********for**debugging***********'@};
	end;
get_avail←p;
end;
@↑changes for {\mc SAIL}@>
@z
@d free_avail(#)== {single-word node liberation}
	begin link(#)←vail; vail←#;
	stat decr(dyn_used);@+tats@/
	end
@↑changes for {\mc SAIL}@>
@z
@p function get_node(@!s:integer):pointer; {variable-size node liberation}
label found,exit;
var p:pointer; {the node currently under inspection}
@!q:pointer; {the node physically after node |p|}
@!r:integer; {the newly allocated node, or a candidate for this honor}
begin p←rover; {start at some free node in the ring}
repeat @<Try to allocate within node |p| and its physical successors,
	and |goto found| if allocation was possible@>;
p←rlink(p); {move to the next node in the ring}
until p=rover; {repeat until the whole list has been traversed}
if s=@'10000000000 then
	begin get_node←max_halfword; return;
	end;
overflow("var size",hi_mem_base-mem_base); {sorry, nothing satisfactory is left}
found: link(r)←null; {this node is now nonempty}
stat var_used←var_used+s; {maintain usage statistics}
if var_used>max_var_used then max_var_used←var_used;
tats@;@/
if not was_free[r] then
	begin @{@/
	'*************breakpoint*************';@/
	'***********for**debugging***********'@};
	end;
get_node←r;
exit:end;
@↑changes for {\mc SAIL}@>
@z
@ @<Try to allocate...@>=
q←p+node_size(p); {find the physical successor}
while false do {merge |p| with |q|}
	begin remove_node(q); q←q+node_size(q);
	end;
r←q-s;
if r>p+1 then @<Allocate from top of node |p| and |goto found|@>;
if (r=p) and ((rlink(p)≠rover) or (llink(p)≠rover)) then
	@<Allocate entire node |p| and |goto found|@>;
node_size(p)←q-p {reset the size in case it grew}
@↑changes for {\mc SAIL}@>
@z
@ @<Check single-word...@>=
p←vail; q←null; clobbered←false;
while p≠null do
	begin if (p>mem_end)∨(p<second_mem) then clobbered←true
	else if free[p] then clobbered←true;
	if clobbered then
		begin print_nl("AVAIL list clobbered at ");
@.AVAIL list clobbered...@>
		print_int(q); goto done1;
		end;
	free[p]←true; q←p; p←link(q);
	end;
done1:
@↑changes for {\mc SAIL}@>
@z
15: begin font_in_short_display←undefined_font; short_display(n);
	end;
16: begin rewrite(free_file,'FREE.TMP');
	for k←0 to mem_max do
		begin free_file↑←free[k]; put(free_file);
		end;
	end;
@↑system dependencies@>@↑changes for {\mc SAIL}@>
@z
@* \[54] System-dependent changes.
Here are the remaining things needed to make the implementation
complete at {\mc SAIL}.
@↑system dependencies@>@↑changes for {\mc SAIL}@>

@ The |pseudo_typein| variable is set nonzero if the |error| routine
uses the `\.E' option to exit and edit.

@<Glob...@>=
@!pseudo_typein:str_number;

@ @<Set init...@>=
pseudo_typein←0; page←0;

@ Freed nodes go into |vail| instead of |avail|, so there is no recycling.
An auxiliary |free_file| is used to record memory usage.

@<Glob...@>=
@!vail:pointer;
@!free_file:file of boolean;

@ @<Set init...@>=
reset(free_file,'FREE.TMP','/O');
if not eof(free_file) then
	begin for k←0 to mem_max do
		begin was_free[k]←free_file↑; get(free_file);
		end;
	end;

@z